<?php
vendor('bc');

class Pass extends AppModel
{

	var $name = 'Pass';

	var $type = array(
	   'REFILL_ACCOUNT', // Пополнение счёта.
	   'PAYMENT_TEST', // Запуск процедуры работы с Инструментом
	   'PAYMENT_BLANK_PRINT', // Генерация бланка для распечатки
	   'PAYMENT_REPORT', // Формирование отчета по Инструментам (стоимость формирования разных видов отчетов по одному опроснику — различная)
	   'PAYMENT_CONSOLIDATED_REPORT', // Формирование консолидированного отчета по результатам тестирования нескольких пользователей
	);

	var $validate = array(
	);

	var $belongsTo = array(
		'Client'         => array('className' => 'Client', 'type' => 'INNER'),
		'ClientAdmin'    => array('className' => 'ClientAdmin'),
		'Admin'          => array('className' => 'Admin'),
		'Candidate'      => array('className' => 'Candidate'),
		'Testing'        => array('className' => 'Testing'),
		'Reporting'      => array('className' => 'Reporting'),
		'Test'           => array('className' => 'Test'),
	);

	function exec($type, $client_id, DomainAmount $amount, DomainAmount $balance_before, $params = array())
	{
		if (!in_array($type, $this->type) || !isset($client_id) || !isset($balance_before)) {
			throw new Exception("Not enough data to conduct transactions", 1010);
		}

		$admin_id = null;
		$client_admin_id = null;
		if (Auth::o()->is('admin')) {
		    $admin_id = Auth::o()->realId();
		} else {
		    $client_admin_id = Auth::o()->realId();
		}

		$credit       = 'N';
		$testing_id   = isset($params['testing_id'])   ? $params['testing_id']   : null;
		$reporting_id = isset($params['reporting_id']) ? $params['reporting_id'] : null;
		$candidate_id = isset($params['candidate_id']) ? $params['candidate_id'] : null;
		$comment      = isset($params['comment']) ? $params['comment'] : null;
		$bill         = null;

		switch ($type) {

	    case 'REFILL_ACCOUNT':
            $testing_id       = null;
            $reporting_id     = null;
    		$credit           = 'Y';
    		$bill = '';
            $candidate_id = null;
    		if (isset($params['bill']) && is_string($params['bill'])) {
    		    $bill = $params['bill'];
    		}
            break;

	    case 'PAYMENT_TEST':
            if (!isset($testing_id) || !isset($candidate_id)) {
                throw new Exception("Not enough data to conduct transactions", 1019);
            }
            $reporting_id = null;
            break;

	    case 'PAYMENT_REPORT':
            if (!isset($reporting_id) || !isset($candidate_id)) {
                throw new Exception("Not enough data to conduct transactions", 1023);
            }
            $testing_id = null;
            break;

        case 'PAYMENT_CONSOLIDATED_REPORT':
            if (!isset($reporting_id)) {
                throw new Exception("Not enough data to conduct transactions", 1028);
            }
            $candidate_id = null;
            $testing_id = null;
            break;

	    case 'PAYMENT_BLANK_PRINT':
            if (!isset($candidate_id) || ! isset($testing_id)) {
                throw new Exception("Not enough data to conduct transactions", 1022);
            }
            $reporting_id = null;
            break;
		}

	    $Client =& $this->getModel('Client'); /* @var $Client Client */
	    $Client->id = $client_id;
		if ($credit == "Y") {
    		$new_balance = DomainAmount(bc::add($balance_before->value, $amount->value));
		} else {
            $free_balance = $Client->getFreeBalance($client_id, $type == 'PAYMENT_TEST' ? $testing_id : null);
    	    if (bc::lt($free_balance->value, $amount->value)) {
    	        throw new Exception("Insufficient balance", 1002);
    	    }
    		$new_balance = DomainAmount(bc::sub($balance_before->value, $amount->value));
		}

		$data = array($this->name => array(
			'type'               => $type,
			'client_id'          => $client_id,
			'admin_id'           => $admin_id,
			'client_admin_id'    => $client_admin_id,
			'testing_id'         => $testing_id,
			'reporting_id'       => $reporting_id,
			'created'            => Date::Unix2SQL(time()),
			'amount'             => $amount->toSQL(),
			'balance_before'     => $balance_before->toSQL(),
			'credit'             => $credit,
			'bill'               => $bill,
			'candidate_id'       => $candidate_id,
			'comment'            => $comment,
		));
		if ($this->save($this->create($data))) {
			$data[$this->name][$this->primaryKey] = $this->getLastInsertID();
    		if (! $Client->save(array($Client->name => array('balance' => $new_balance->value)))) {
    		    throw new Exception("Unable to change client balance", 1004);
    		}
		} else {
			throw new Exception("Unable to create transaction", 1011);
		}
	}

	function allowUpdate()
	{
	    return false;
	}

	function allowDelete()
	{
	    return false;
	}

	function getTypes()
	{
		return $this->type;
	}

	function getTypesList()
	{
		$result = array();
		foreach ($this->type as $type) {
			$result[$type] = __d('passes', 'type_'.$type, true);
		}
	    return $result;
	}

	/**
	 * Кеширование test_id, для оптимизации.
	 *
	 * Необходимые изменение БД:
	 * ALTER TABLE `passes` ADD `test_id` INT UNSIGNED NULL;
	 * ALTER TABLE `passes` ADD INDEX `test` ( `test_id` );
	 * UPDATE `passes` p LEFT JOIN `testings` AS t ON p.`testing_id` = t.`id` LEFT JOIN `reportings` r ON p.`reporting_id` = r.`id` LEFT JOIN `testings` rt ON r.`testing_id` = rt.`id`  SET p.`test_id` = IF( t.`test_id` IS NULL , rt.`test_id` , t.`test_id` );
	 */
	function beforeSave()
	{
	    if (! $this->exists()) {
	        $test_id = null;
	        if (isset($this->data[$this->name]['testing_id'])) {
                $Testing =& $this->getModel('Testing'); /* @var $Testing Testing */
                $Testing->rel();
                $tmp = $Testing->read("test_id", $this->data[$this->name]['testing_id']);
                if (! empty($tmp[$Testing->name]["test_id"])) {
                    $test_id = $tmp[$Testing->name]["test_id"];
                }
	        } elseif (isset($this->data[$this->name]['reporting_id'])) {
                $Reporting =& $this->getModel('Reporting'); /* @var $Reporting Reporting */
                $Reporting->rel("Testing");
                $tmp = $Reporting->read("Testing.test_id", $this->data[$this->name]['reporting_id']);
                if (! empty($tmp["Testing"]["test_id"])) {
                    $test_id = $tmp["Testing"]["test_id"];
                }
	        }
	        $this->data[$this->name]['test_id'] = $test_id;
	    }

	    return parent::beforeSave();
	}
}

?>